﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using Groundwork.Extensions;
using FluentAssertions;
using System.Collections.ObjectModel;
using System.Text;

namespace ExtensionMethods.Test.Extensions
{
    [TestClass]
    public class CollectionsTest
    {
        List<string> targetString;
        List<string> targetIntString;
        List<char> targetChar;
        [TestInitialize]
        public void setup()
        {
            targetString = new List<string> { "a", "b", "c", "d", "e", "f", "g" };
            targetIntString = new List<string> { "1", "2", "3", "4", "5", "6", "7" };
            targetChar = new List<char> { '1', '2', '3', '4', '5', '6', '7' };
        }

        [TestMethod]
        public void TestListSplitting()
        {
            
            List<List<string>> parts = targetString.Split(2);
            parts.Count.Should().Be(4);

            parts[0].Count.Should().Be(2);
            parts[0][0].Should().Be("a");
            parts[0][1].Should().Be("b");

            parts[1].Count.Should().Be(2);
            parts[1][0].Should().Be("c");
            parts[1][1].Should().Be("d");

            parts[2].Count.Should().Be(2);
            parts[2][0].Should().Be("e");
            parts[2][1].Should().Be("f");

            parts[3].Count.Should().Be(1);
            parts[3][0].Should().Be("g");
        }

        [TestMethod]
        public void TestListToObservableStringCollectionConversion()
        {            
            ObservableCollection<string> converted = targetString.ToObservable<string>();
            converted.Should().NotBeNull();
            converted.Count.Should().Be(7);
            converted[0].Should().Be("a");
        }

        [TestMethod]
        public void TestListToObservableIntCollectionConversion()
        {
            List<int> target = new List<int> { 1,2,3,4,5,6,7};
            ObservableCollection<int> converted = target.ToObservable<int>();
            converted.Should().NotBeNull();
            converted.Count.Should().Be(7);
            converted[0].Should().Be(1);
        }


        [TestMethod]
        public void TestListToObservableTypeConvertCollectionConversion()
        {
            ObservableCollection<int> converted = targetIntString.ToObservable<string, int>();
            converted.Should().NotBeNull();
            converted.Count.Should().Be(7);
            converted[0].Should().Be(1);
        }

        [TestMethod]
        public void TestCharListForEach_ExceptionRaisedOnElementProcess()
        {
            
            bool exceptionTriggered = false;

            Action<Exception> onError = (ex)=>
            {
                exceptionTriggered = true;
            };

            Action<char> process = (arg) =>
            {
                if (arg == '3')
                {
                    throw new NullReferenceException();
                }
            };

            targetChar.ForEach(process, onError);

            exceptionTriggered.Should().BeTrue();
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void TestExceptionThrowCharListForEach_ExceptionRaisedOnElementProcess()
        {
            Action<char> process = (arg) =>
            {
                if (arg == '3')
                {
                    throw new NullReferenceException();
                }
            };

            targetChar.ForEach(process);
        }

        [TestMethod]
        public void TestCharListForEach_ProcessListOfChars()
        {
            StringBuilder builder = new StringBuilder();
            
            bool exceptionTriggered = false;

            Action<Exception> onError = (ex) =>
            {
                exceptionTriggered = true;
            };

            
            Action<char> process = (arg) =>
            {
                builder.Append(arg);
            };

            targetChar.ForEach(process, onError);

            exceptionTriggered.Should().BeFalse();
            builder.ToString().Should().Be("1234567");
        }

        [TestMethod]
        public void TestStringListForEach_ExceptionRaisedOnElementProcess()
        {
            
            bool exceptionTriggered = false;

            Action<Exception> onError = (ex) =>
            {
                exceptionTriggered = true;
            };

            Action<string> process = (arg) =>
            {
                throw new NullReferenceException();
            };

            targetString.ForEach(process, onError);

            exceptionTriggered.Should().BeTrue();
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void TestExceptionThrowStringListForEach_ExceptionRaisedOnElementProcess()
        {
            Action<string> process = (arg) =>
            {
               throw new NullReferenceException();
            };

            targetString.ForEach(process);
        }

        [TestMethod]
        public void TestStringListForEach_ProcessListOfChars()
        {
            StringBuilder builder = new StringBuilder();
  
            Action<string> process = (arg) =>
            {
                builder.Append(arg);
            };

            targetString.ForEach(process);

            builder.ToString().Should().Be("abcdefg");
        }

        [TestMethod]
        public void TestObservableCollectionForEach_ProcessListOfChars()
        {
            StringBuilder builder = new StringBuilder();
            ObservableCollection<string> target = new ObservableCollection<string>() { "1", "2", "3", "4", "5", "6", "7" };
            bool exceptionTriggered = false;

            Action<Exception> onError = (ex) =>
            {
                exceptionTriggered = true;
            };


            Action<string> process = (arg) =>
            {
                builder.Append(arg);
            };

            target.ForEach<string>(process, onError);

            exceptionTriggered.Should().BeFalse();
            builder.ToString().Should().Be("1234567");
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void TestExceptionThrowObservableCollectionForEach_ProcessListOfChars()
        {
            StringBuilder builder = new StringBuilder();
            ObservableCollection<string> target = new ObservableCollection<string>() { "1", "2", "3", "4", "5", "6", "7" };
            
            Action<string> process = (arg) =>
            {
                throw new NullReferenceException();
            };

            target.ForEach<string>(process);
        }



    }
}
